package etc.netty.client;

import com.dmz.test.etc.config.DmzProp;
import com.dmz.test.etc.domain.ClientTask;
import com.dmz.test.etc.netty.attr.ChannelAttrs;
import com.dmz.test.etc.netty.attr.ChannelMatchMap;
import com.dmz.test.etc.utils.SpringUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author lee
 */
@Slf4j
public class NettyClient {

    public Channel start(NioEventLoopGroup wg, ChannelHandlerContext ctx) throws Exception {

        Bootstrap b = new Bootstrap();
        Channel channel = ctx.channel();
        ChannelAttrs.Address address = channel.attr(ChannelAttrs.address).get();
        Integer forward = channel.attr(ChannelAttrs.forward).get();
        b.group(wg)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) {
                        ChannelPipeline p = ch.pipeline();
                        p.addLast(new ByteArrayDecoder());
                        if (forward == 1) {
                            p.addLast(new StringEncoder());
                        } else {
                            p.addLast(new ByteArrayEncoder());
                        }
                        //p.addLast(new ByteArrayEncoder());
                        p.addLast(new ClientHandler(channel)); // 传递回clientChannel以便回复客户端A
                    }
                });

        ChannelFuture future = b.connect(address.getHost(), address.getPort());
        // 等待连接完成，但不在这个方法中同步等待，以避免阻塞
        // 你可以在一个单独的线程中等待，或者使用回调机制来处理连接结果
        Channel c = future.sync().channel();
        ChannelMatchMap.addClientChannel(channel.id(), c);
        log.info("server start client Connected to server: {}", c.remoteAddress());
        return c;
    }

    public void start(ClientTask task) throws Exception {
        DmzProp dmzProp = SpringUtil.getBean(DmzProp.class);
        Bootstrap b = new Bootstrap();
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new ByteArrayDecoder());
                            p.addLast(new ByteArrayEncoder());
                            //p.addLast(new ByteArrayEncoder());
                            p.addLast(new TaskHandler(task)); // 传递回clientChannel以便回复客户端A
                        }
                    });
            String etcHosts = dmzProp.getEtcHosts();
            List<String> hosts = Arrays.asList(Objects.requireNonNull(etcHosts).split(","));
            String etcPorts = dmzProp.getEtcPorts();
            List<String> ports = Arrays.asList(Objects.requireNonNull(etcPorts).split(","));
            for (int i = 0; i < hosts.size(); i++) {
                try {
                    ChannelFuture future = b.connect(hosts.get(i), Integer.parseInt(ports.get(i))).sync();
                    //future.channel().attr(ChannelAttrs.clientTask).set(task);
                    log.info("task client Connected to server: {}", future.channel().remoteAddress());
                    // 等待客户端通道关闭
                    future.channel().closeFuture().sync();
                    return;
                } catch (Exception e) {
                    log.error("server client start error", e);
                }
            }
        }finally {
            // 优雅关闭
            group.shutdownGracefully();
        }
    }
}
